<!DOCTYPE html>
<html>
<head>
    <title>音频录制测试</title>
</head>
<body>
    <h1>音频录制测试</h1>
    <button id="startRecord">开始录制</button>
    <button id="stopRecord" disabled>停止录制</button>
    <button id="uploadRecord" disabled>上传录制音频</button>
    <br><br>
    <input type="file" id="fileInput" accept="audio/*">
    <button id="uploadFile">上传文件</button>
    <br><br>
    <div id="status"></div>
    <div id="result"></div>

    <script>
        let mediaRecorder;
        let audioChunks = [];
        let recordedBlob;

        const startBtn = document.getElementById('startRecord');
        const stopBtn = document.getElementById('stopRecord');
        const uploadRecordBtn = document.getElementById('uploadRecord');
        const fileInput = document.getElementById('fileInput');
        const uploadFileBtn = document.getElementById('uploadFile');
        const status = document.getElementById('status');
        const result = document.getElementById('result');

        startBtn.onclick = async () => {
            try {
                const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
                mediaRecorder = new MediaRecorder(stream);
                audioChunks = [];

                mediaRecorder.ondataavailable = event => {
                    audioChunks.push(event.data);
                };

                mediaRecorder.onstop = () => {
                    // 原始录制的音频
                    const originalBlob = new Blob(audioChunks, { type: mediaRecorder.mimeType });
                    status.innerHTML = `原始录制完成，类型: ${originalBlob.type}, 大小: ${originalBlob.size} bytes`;
                    
                    // 检查原始格式
                    checkAudioFormat(originalBlob, '原始录制');
                    
                    // 转换为WAV格式
                    convertToWav(originalBlob).then(wavBlob => {
                        recordedBlob = wavBlob;
                        status.innerHTML += `<br>转换后，类型: ${wavBlob.type}, 大小: ${wavBlob.size} bytes`;
                        checkAudioFormat(wavBlob, '转换后');
                        uploadRecordBtn.disabled = false;
                    }).catch(error => {
                        status.innerHTML += `<br>转换失败: ${error.message}`;
                        recordedBlob = originalBlob;
                        uploadRecordBtn.disabled = false;
                    });
                };

                mediaRecorder.start();
                startBtn.disabled = true;
                stopBtn.disabled = false;
                status.innerHTML = '正在录制...';
            } catch (error) {
                status.innerHTML = '录制失败: ' + error.message;
            }
        };

        stopBtn.onclick = () => {
            mediaRecorder.stop();
            mediaRecorder.stream.getTracks().forEach(track => track.stop());
            startBtn.disabled = false;
            stopBtn.disabled = true;
        };

        uploadRecordBtn.onclick = async () => {
            await uploadAudio(recordedBlob, 'recorded_audio.wav');
        };

        uploadFileBtn.onclick = async () => {
            const file = fileInput.files[0];
            if (file) {
                await uploadAudio(file, file.name);
            } else {
                result.innerHTML = '请选择文件';
            }
        };

        function checkAudioFormat(audioBlob, label) {
            const reader = new FileReader();
            reader.onload = function() {
                const arrayBuffer = reader.result;
                const uint8Array = new Uint8Array(arrayBuffer);
                const header = Array.from(uint8Array.slice(0, 12)).map(b => String.fromCharCode(b)).join('');
                status.innerHTML += `<br>${label}文件头: ${header}`;
                
                // 检查是否为真正的WAV格式
                if (header.startsWith('RIFF') && header.includes('WAVE')) {
                    status.innerHTML += `<br>✓ ${label}是真正的WAV格式`;
                } else {
                    status.innerHTML += `<br>✗ ${label}不是真正的WAV格式，可能是WebM或其他格式`;
                }
            };
            reader.readAsArrayBuffer(audioBlob);
        }

        // 音频格式转换函数
        async function convertToWav(audioBlob) {
            return new Promise((resolve, reject) => {
                const audioContext = new (window.AudioContext || window.webkitAudioContext)();
                const fileReader = new FileReader();
                
                fileReader.onload = function(e) {
                    audioContext.decodeAudioData(e.target.result)
                        .then(audioBuffer => {
                            const wavBlob = audioBufferToWav(audioBuffer);
                            resolve(wavBlob);
                        })
                        .catch(reject);
                };
                
                fileReader.onerror = reject;
                fileReader.readAsArrayBuffer(audioBlob);
            });
        }

        // 将AudioBuffer转换为WAV格式
        function audioBufferToWav(buffer) {
            const length = buffer.length;
            const numberOfChannels = buffer.numberOfChannels;
            const sampleRate = buffer.sampleRate;
            const arrayBuffer = new ArrayBuffer(44 + length * numberOfChannels * 2);
            const view = new DataView(arrayBuffer);
            
            // WAV文件头
            const writeString = (offset, string) => {
                for (let i = 0; i < string.length; i++) {
                    view.setUint8(offset + i, string.charCodeAt(i));
                }
            };
            
            writeString(0, 'RIFF');
            view.setUint32(4, 36 + length * numberOfChannels * 2, true);
            writeString(8, 'WAVE');
            writeString(12, 'fmt ');
            view.setUint32(16, 16, true);
            view.setUint16(20, 1, true);
            view.setUint16(22, numberOfChannels, true);
            view.setUint32(24, sampleRate, true);
            view.setUint32(28, sampleRate * numberOfChannels * 2, true);
            view.setUint16(32, numberOfChannels * 2, true);
            view.setUint16(34, 16, true);
            writeString(36, 'data');
            view.setUint32(40, length * numberOfChannels * 2, true);
            
            // 写入音频数据
            let offset = 44;
            for (let i = 0; i < length; i++) {
                for (let channel = 0; channel < numberOfChannels; channel++) {
                    const sample = Math.max(-1, Math.min(1, buffer.getChannelData(channel)[i]));
                    view.setInt16(offset, sample < 0 ? sample * 0x8000 : sample * 0x7FFF, true);
                    offset += 2;
                }
            }
            
            return new Blob([arrayBuffer], { type: 'audio/wav' });
        }

        async function uploadAudio(audioBlob, filename) {
            const formData = new FormData();
            formData.append('groupId', 'group001');
            formData.append('featureId', 'test_user_' + Date.now());
            formData.append('featureInfo', 'test feature');
            formData.append('audioFile', audioBlob, filename);

            try {
                result.innerHTML = '正在上传...';
                const response = await fetch('http://localhost:8082/api/voiceprint/feature/add', {
                    method: 'POST',
                    body: formData
                });

                const responseText = await response.text();
                result.innerHTML = `<h3>响应结果:</h3><pre>${responseText}</pre>`;
            } catch (error) {
                result.innerHTML = '上传失败: ' + error.message;
            }
        }
    </script>
</body>
</html>